/*----------------------------------------------------------------------------\
|                        Slider 1.02 - Servoy Stuff 1.0                       |
|-----------------------------------------------------------------------------|
|                         Created by Erik Arvidsson                           |
|                  (http://webfx.eae.net/contact.html#erik)                   |
|                      For WebFX (http://webfx.eae.net/)                      |
|-----------------------------------------------------------------------------|
| A  slider  control that  degrades  to an  input control  for non  supported |
| browsers.                                                                   |
|-----------------------------------------------------------------------------|
|                Copyright (c) 2002, 2003, 2006 Erik Arvidsson                |
|-----------------------------------------------------------------------------|
| Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| use this file except in compliance with the License.  You may obtain a copy |
| of the License at http://www.apache.org/licenses/LICENSE-2.0                |
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| Unless  required  by  applicable law or  agreed  to  in  writing,  software |
| distributed under the License is distributed on an  "AS IS" BASIS,  WITHOUT |
| WARRANTIES OR  CONDITIONS OF ANY KIND,  either express or implied.  See the |
| License  for the  specific language  governing permissions  and limitations |
| under the License.                                                          |
|-----------------------------------------------------------------------------|
| Dependencies: timer.js - an OO abstraction of timers                        |
|               range.js - provides the data model for the slider             |
|               winclassic.css or any other css file describing the look      |
|-----------------------------------------------------------------------------|
| 2002-10-14 | Original version released                                      |
| 2003-03-27 | Added a test in the constructor for missing oElement arg       |
| 2003-11-27 | Only use mousewheel when focused                               |
| 2006-05-28 | Changed license to Apache Software License 2.0.                |
|-----------------------------------------------------------------------------|
| Created 2002-10-14 | All changes are in the log above. | Updated 2006-05-28 |
|-----------------------------------------------------------------------------|
| Modified by Servoy Stuff - http://www.servoy-stuff.net/                     |
| For use in Servoy Wicket component | All changes in the log below           |	
|-----------------------------------------------------------------------------|
| 2009-06-25 | Added inverted flag                                            |
| 2009-06-26 | Adapted key and mouse behaviors                                |
| 2009-06-27 | Added ticks flags and values                                   |
| 2009-06-28 | Added Ticks support                                            |
| 2009-07-10 | Added snapToTicks support                                      |
| 2009-07-10 | Added paintLabels support                                      |
| 2009-07-10 | Added paintTrack support                                       |
| 2009-07-10 | Added enabled support                                          |
| 2009-07-10 | Added precision value                                          |
| 2009-07-10 | Added usingDecimals flag                                       |
| 2009-07-15 | Added full images for luna css (disabled/ticks)                |
| 2009-07-23 | Added precision factor support                                 |
| 2009-07-24 | Added support for styleType offsets                            |
| 2009-07-30 | Adjustments for integration in Servoy's Wicket                 |
| 2009-07-31 | Bug fixes                                                      |
| 2009-08-02 | Bug fixes                                                      |
\----------------------------------------------------------------------------*/


Slider.isSupported = typeof document.createElement != "undefined" &&
	typeof document.documentElement != "undefined" &&
	typeof document.documentElement.offsetWidth == "number";


function Slider(oElement, oInput, sOrientation) {
	if (!oElement) return;
	this._orientation = sOrientation || "horizontal";
	this._range = new Range();
	this._range.setExtent(0);
	this._blockIncrement = 10;
	this._unitIncrement = 1;
	this._timer = new Timer(100);
	this._inverted = false;
	this._paintTicks = false;
	this._paintLabels = false;
	this._paintTrack = true;
	this._majorTickSpacing = 10;
	this._minorTickSpacing = 0;
	this._snapToTicks = true;
	this._precision = 0;
	this._usingDecimals = false;
	this._enabled = true;
	this._styleType = "luna"; // "swing"

	if (Slider.isSupported && oElement) {

		oElement.className = this._orientation;
		
		this.document = oElement.ownerDocument || oElement.document;

		this.element = oElement;
		this.element.slider = this;
		this.element.unselectable = "on";

		// add class name tag to class name
		this.element.className = this._orientation + " " + this.classNameTag + " " + this.element.className;

		// create line
		this.line = this.document.createElement("DIV");
		this.line.className = "line";
		this.line.unselectable = "on";
		this.line.appendChild(this.document.createElement("DIV"));
		this.element.appendChild(this.line);
		
		// create ticks
		this.ticks = new Array();
		// create labels
		this.labels = new Array();

		// create handle
		this.handle = this.document.createElement("DIV");
		this.handle.className = "handle";
		this.handle.unselectable = "on";
		this.handle.appendChild(this.document.createElement("DIV"));
		this.handle.firstChild.appendChild(
		this.document.createTextNode(String.fromCharCode(160)));
		this.element.appendChild(this.handle);
	}

	this.input = oInput;
	this.initEvents();
}

Slider.eventHandlers = {

	// helpers to make events a bit easier
	getEvent:	function (e, el) {
		if (!e) {
			if (el)
				e = el.document.parentWindow.event;
			else
				e = window.event;
		}
		if (!e.srcElement) {
			var el = e.target;
			while (el != null && el.nodeType != 1)
				el = el.parentNode;
			e.srcElement = el;
		}
		if (typeof e.offsetX == "undefined") {
			e.offsetX = e.layerX;
			e.offsetY = e.layerY;
		}

		return e;
	},

	getDocument:	function (e) {
		if (e.target)
			return e.target.ownerDocument;
		return e.srcElement.document;
	},

	getSlider:	function (e) {
		var el = e.target || e.srcElement;
		while (el != null && el.slider == null)	{
			el = el.parentNode;
		}
		if (el)
			return el.slider;
		return null;
	},

	getLine:	function (e) {
		var el = e.target || e.srcElement;
		while (el != null && el.className != "line")	{
			el = el.parentNode;
		}
		return el;
	},

	getHandle:	function (e) {
		var el = e.target || e.srcElement;
		var re = /handle/;
		while (el != null && !re.test(el.className))	{
			el = el.parentNode;
		}
		return el;
	},
	// end helpers

	onfocus:	function (e) {
		var s = this.slider;
		s._focused = true;
		s.handle.className = "handle hover";
	},

	onblur:	function (e) {
		var s = this.slider
		s._focused = false;
		window.status = "";
		s.handle.className = "handle";
	},

	onmouseover:	function (e) {
		e = Slider.eventHandlers.getEvent(e, this);
		var s = this.slider;
		if (e.srcElement == s.handle)
			s.handle.className = "handle hover";
	},

	onmouseout:	function (e) {
		e = Slider.eventHandlers.getEvent(e, this);
		var s = this.slider;
		if (e.srcElement == s.handle && !s._focused)
			s.handle.className = "handle";
	},

	onmousedown:	function (e) {
		e = Slider.eventHandlers.getEvent(e, this);
		var s = this.slider;
		if (s.element.focus)
			s.element.focus();

		Slider._currentInstance = s;
		var doc = s.document;

		if (doc.addEventListener) {
			doc.addEventListener("mousemove", Slider.eventHandlers.onmousemove, true);
			doc.addEventListener("mouseup", Slider.eventHandlers.onmouseup, true);
		}
		else if (doc.attachEvent) {
			doc.attachEvent("onmousemove", Slider.eventHandlers.onmousemove);
			doc.attachEvent("onmouseup", Slider.eventHandlers.onmouseup);
			doc.attachEvent("onlosecapture", Slider.eventHandlers.onmouseup);
			s.element.setCapture();
		}

		if (Slider.eventHandlers.getHandle(e)) {	// start drag
			Slider._sliderDragData = {
				screenX:	e.screenX,
				screenY:	e.screenY,
				dx:		e.screenX - s.handle.offsetLeft,
				dy:		e.screenY - s.handle.offsetTop,
				startValue:	s.getValue(),
				slider:		s
			};
		}
		else {
			var lineEl = Slider.eventHandlers.getLine(e);
			s._mouseX = e.offsetX + (lineEl ? s.line.offsetLeft : 0);
			s._mouseY = e.offsetY + (lineEl ? s.line.offsetTop : 0);
			s._increasing = null;
			s.ontimer();
		}
	},

	onmousemove:	function (e) {
		e = Slider.eventHandlers.getEvent(e, this);

		if (Slider._sliderDragData) {	// drag
			var s = Slider._sliderDragData.slider;

			var boundSize = s.getMaximum() - s.getMinimum();
			var size, pos, reset;

			if (s._orientation == "horizontal") {
				size = s.element.offsetWidth - s.handle.offsetWidth;
				pos = e.screenX - Slider._sliderDragData.dx;
				reset = Math.abs(e.screenY - Slider._sliderDragData.screenY) > 100;
			}
			else {
				size = s.element.offsetHeight - s.handle.offsetHeight;
				pos = s.element.offsetHeight - s.handle.offsetHeight - 
					(e.screenY - Slider._sliderDragData.dy);
				reset = Math.abs(e.screenX - Slider._sliderDragData.screenX) > 100;
			}
			var val = (s.getMinimum() + boundSize) * pos / size;
			var newValue = (s._inverted) ? s.getMaximum() - val: val;
			s.setValue(reset ? Slider._sliderDragData.startValue : newValue );
			return false;
		}
		else {
			var s = Slider._currentInstance;
			if (s != null) {
				var lineEl = Slider.eventHandlers.getLine(e);
				s._mouseX = e.offsetX + (lineEl ? s.line.offsetLeft : 0);
				s._mouseY = e.offsetY + (lineEl ? s.line.offsetTop : 0);
			}
		}

	},

	onmouseup:	function (e) {
		e = Slider.eventHandlers.getEvent(e, this);
		var s = Slider._currentInstance;
		var doc = s.document;
		if (doc.removeEventListener) {
			doc.removeEventListener("mousemove", Slider.eventHandlers.onmousemove, true);
			doc.removeEventListener("mouseup", Slider.eventHandlers.onmouseup, true);
		}
		else if (doc.detachEvent) {
			doc.detachEvent("onmousemove", Slider.eventHandlers.onmousemove);
			doc.detachEvent("onmouseup", Slider.eventHandlers.onmouseup);
			doc.detachEvent("onlosecapture", Slider.eventHandlers.onmouseup);
			s.element.releaseCapture();
		}

		if (Slider._sliderDragData) {	// end drag
			Slider._sliderDragData = null;
			var cValue = s.getValue();
			if (s._snapToTicks) {
				var inc = (s._minorTickSpacing > 0) ? s._minorTickSpacing : s._majorTickSpacing;
				if (inc > 0) {
					var diff =  cValue % inc;
					if (diff > 0) {
						var min = cValue - diff;
						var max = min + inc;
						var diff2 = max - cValue;
						cValue = (diff > diff2) ? max : min;
					}
				}
			}
			s.setValue(cValue);
		}
		else {
			s._timer.stop();
			s._increasing = null;
		}
		window.status = "";
		Slider._currentInstance = null;
	},

	onkeydown:	function (e) {
		e = Slider.eventHandlers.getEvent(e, this);
		//var s = Slider.eventHandlers.getSlider(e);
		var s = this.slider;
		var kc = e.keyCode;
		switch (kc) {
			case 33:	// page up
				s.setValue(s.getValue() + (((s.getOrientation() == "vertical" && s._inverted) || 
				(s.getOrientation() == "horizontal" && !s._inverted)) 
				? (0 - s.getBlockIncrement()) : s.getBlockIncrement()) );
				break;
			case 34:	// page down
				s.setValue(s.getValue() + (((s.getOrientation() == "vertical" && s._inverted) || 
				(s.getOrientation() == "horizontal" && !s._inverted)) 
				? s.getBlockIncrement() : (0 - s.getBlockIncrement())) );
				break;
			case 35:	// end
				s.setValue(s.getOrientation() == "horizontal" ?
					((s._inverted) ? s.getMinimum() : s.getMaximum()) :
					((s._inverted) ? s.getMaximum() : s.getMinimum()));
				break;
			case 36:	// home
				s.setValue(s.getOrientation() == "horizontal" ?
					((s._inverted) ? s.getMaximum() : s.getMinimum()) :
					((s._inverted) ? s.getMinimum() : s.getMaximum()));
				break;
			case 38:	// up
				if ((s.getOrientation() == "vertical" && s._inverted) || 
				(s.getOrientation() == "horizontal" && !s._inverted)) {
					s.setValue(s.getValue() - s.getUnitIncrement());
				} else {
					s.setValue(s.getValue() + s.getUnitIncrement());
				}
				break;
			case 39:	// right
				if (s.getOrientation() == "horizontal" && s._inverted) {
					s.setValue(s.getValue() - s.getUnitIncrement());
				} else {
					s.setValue(s.getValue() + s.getUnitIncrement());
				}
				break;

			case 40:	// down
				if ((s.getOrientation() == "vertical" && s._inverted) || 
				(s.getOrientation() == "horizontal" && !s._inverted)) {
					s.setValue(s.getValue() + s.getUnitIncrement());
				} else {
					s.setValue(s.getValue() - s.getUnitIncrement());
				}
				break;
			case 37:	// left
				if (s.getOrientation() == "horizontal" && s._inverted) {
					s.setValue(s.getValue() + s.getUnitIncrement());
				} else {
					s.setValue(s.getValue() - s.getUnitIncrement());
				}
				break;
		}

		if (kc >= 33 && kc <= 40) {
			return false;
		}
	},

	onkeypress:	function (e) {
		e = Slider.eventHandlers.getEvent(e, this);
		var kc = e.keyCode;
		if (kc >= 33 && kc <= 40) {
			return false;
		}
	},

	onmousewheel:	function (e) {
		e = Slider.eventHandlers.getEvent(e, this);
		var s = this.slider;
		if (s._focused) {
			// windows inverts this on horizontal sliders. That does not make sense to me:
			if (navigator.appVersion.indexOf("Win")!=-1) {
				s.setValue(s.getValue() - e.wheelDelta / 120 * s.getUnitIncrement());
			} else {
				s.setValue(s.getValue() + e.wheelDelta / 120 * s.getUnitIncrement());
			}
			return false;
		}
	}
};



Slider.prototype.classNameTag = "dynamic-slider-control";

Slider.prototype.setValue = function (v) {
	this._range.setValue(v);
	window.status = this.getExternalValue();
	if (!this.isInDrag()) {
		this.input.value = this.getExternalValue();
		if (typeof this.onchange == "function")
				this.onchange();
	}
};

Slider.prototype.getValue = function () {
	return this._range.getValue();
};

Slider.prototype.getExternalValue = function () {
	if (this.usePrecisionFactor()) {
		var v = this._range.getValue() / this.getPrecisionFactor();
		return this.format_number(v);
	} else {
		return this._range.getValue();
	}
};

Slider.prototype.setExternalValue = function (v) {
	if (this.usePrecisionFactor()) {
		this._range.setValue(v * this.getPrecisionFactor());
	} else {
		this._range.setValue(v);
	}
	this.input.value = this.getExternalValue();
};

Slider.prototype.setMinimum = function (v, b) {
	if (this.usePrecisionFactor()) {
		this._range.setMinimum(v * this.getPrecisionFactor());
	} else {
		this._range.setMinimum(v);
	}
	this.input.value = this.getExternalValue();
	if (!b) this.calculateTicks();
};

Slider.prototype.getMinimum = function () {
	return this._range.getMinimum();
};

Slider.prototype.setMaximum = function (v, b) {
	if (this.usePrecisionFactor()) {
		this._range.setMaximum(v * this.getPrecisionFactor());
	} else {
		this._range.setMaximum(v);
	}
	this.input.value = this.getExternalValue();
	if (!b) this.calculateTicks();
};

Slider.prototype.getMaximum = function () {
	return this._range.getMaximum();
};

Slider.prototype.setUnitIncrement = function (v) {
	if (v < 1) v = 1;
	if (this.usePrecisionFactor()) {
		this._unitIncrement = v * this.getPrecisionFactor();
	} else {
		this._unitIncrement = v;
	}
};

Slider.prototype.getUnitIncrement = function () {
	return this._unitIncrement;
};

Slider.prototype.setBlockIncrement = function (v) {
	if (v < 1) v = 1;
	if (this.usePrecisionFactor()) {
		this._blockIncrement = v * this.getPrecisionFactor();
	} else {
		this._blockIncrement = v;
	}
};

Slider.prototype.getBlockIncrement = function () {
	return this._blockIncrement;
};

Slider.prototype.setInverted = function (v) {
	this._inverted = v;
};

Slider.prototype.getInverted = function () {
	return this._inverted;
};

Slider.prototype.setPaintTrack = function(v) {
	this._paintTrack = v;
	this.line.style.display = (v) ? "block" : "none";
}

Slider.prototype.getPaintTrack = function() {
	return this._paintTrack;
}

Slider.prototype.setPaintTicks = function (v) {
	this._paintTicks = v;
	this.updateTickSupport();
};

Slider.prototype.getPaintTicks = function () {
	return this._paintTicks;
};

Slider.prototype.setPaintLabels = function (v) {
	this._paintLabels = v;
	this.updateTickSupport();
};

Slider.prototype.getPaintLabels = function () {
	return this._paintLabels;
};

Slider.prototype.setEnabled = function (v) {
	var mustInit = (this._enabled != v);
	this._enabled = v;
	if (mustInit) {
		this.initEvents();
	}
};

Slider.prototype.isEnabled = function () {
	return this._enabled;
};

Slider.prototype.setSnapToTicks = function (v) {
	this._snapToTicks = v;
};

Slider.prototype.getSnapToTicks = function () {
	return this._snapToTicks;
};

Slider.prototype.setStyleType = function (v) {
	this._styleType = v;
};

Slider.prototype.getStyleType = function () {
	return this._styleType;
};


Slider.prototype.setPrecision = function (v) {
	if (v < 0) v = 0;
	this._precision = v;
	this.updatePrecision();
};

Slider.prototype.getPrecision = function () {
	return this._precision;
};

Slider.prototype.getPrecisionFactor = function () {
	return Math.pow(10.0, this._precision);
};

Slider.prototype.setUsingDecimals = function (v) {
	this._usingDecimals = v;
	this.updatePrecision();
};
		
Slider.prototype.updatePrecision = function() {
	this.setMinimum(this.getMinimum(), true);
	this.setMaximum(this.getMaximum(), true);
	this.setMajorTickSpacing(this.getMajorTickSpacing(), true);
	this.setMinorTickSpacing(this.getMinorTickSpacing(), true);
	this.setUnitIncrement(this.getUnitIncrement());
	this.setBlockIncrement(this.getBlockIncrement());
	this.setValue(this.getValue());
	this.recalculate();
	this.updateTickSupport();
}

Slider.prototype.isUsingDecimals = function () {
	return this._usingDecimals;
};

Slider.prototype.usePrecisionFactor = function () {
	return (this._usingDecimals && this._precision > 0);
}

Slider.prototype.setMajorTickSpacing = function (v, b) {
	if (v < 0) v = 0;
	if (this.usePrecisionFactor()) {
		this._majorTickSpacing = v * this.getPrecisionFactor();
	} else {
		this._majorTickSpacing = v;
	}
	if (!b) this.updateTickSupport();
};

Slider.prototype.getMajorTickSpacing = function () {
	return this._majorTickSpacing;
};

Slider.prototype.setMinorTickSpacing = function (v, b) {
	if (v < 0) v = 0;
	if (this.usePrecisionFactor()) {
		this._minorTickSpacing = v * this.getPrecisionFactor();
	} else {
		this._minorTickSpacing = v;
	}
	if (!b) this.updateTickSupport();
};

Slider.prototype.getMinorTickSpacing = function () {
	return this._minorTickSpacing;
};

Slider.prototype.updateTickSupport = function () {
	if (Slider.isSupported && this.element) {
		if (this.hasTicks()) {
			if (this.element.className.indexOf("ticks") < 0) {
				this.element.className = "ticks " + this.element.className;
			}
		} else {
			this.element.className = this.element.className.replace("ticks", "");
		}
		this.calculateTicks();
	}
};

Slider.prototype.updateEnabledSupport = function () {
	if (Slider.isSupported && this.element) {
		if (!this.isEnabled()) {
			if (this.element.className.indexOf("disabled") < 0) {
				this.element.className = "disabled " + this.element.className;
			}
		} else {
			this.element.className = this.element.className.replace("disabled", "");
		}
	}
};

Slider.prototype.hasTicks = function () {
	return this._paintTicks && (this._majorTickSpacing > 0 || this._minorTickSpacing > 0);
};

Slider.prototype.getOrientation = function () {
	return this._orientation;
};

Slider.prototype.setOrientation = function (sOrientation) {
	if (sOrientation != this._orientation) {
		if (Slider.isSupported && this.element) {
			// add class name tag to class name
			this.element.className = this.element.className.replace(this._orientation,
									sOrientation);
		}
		this._orientation = sOrientation;
		this.recalculate();

	}
};

Slider.prototype.recalculate = function() {
	if (!Slider.isSupported || !this.element) return;

	var w = this.element.offsetWidth;
	var h = this.element.offsetHeight;
	var hw = this.handle.offsetWidth;
	var hh = this.handle.offsetHeight;
	var lw = this.line.offsetWidth;
	var lh = this.line.offsetHeight;

	// this assumes a border-box layout
	var pos;
	if (this._orientation == "horizontal") {
		if (this._inverted) {
			pos = (w - hw) * ((this.getMaximum()-this.getMinimum()) - (this.getValue() - this.getMinimum())) / (this.getMaximum() - this.getMinimum());
		} else {
			pos = (w - hw) * (this.getValue() - this.getMinimum()) / (this.getMaximum() - this.getMinimum());
		}
		this.handle.style.left = pos + "px";
		this.handle.style.top = (h - hh) / 2 + "px";

		this.line.style.top = (h - lh) / 2 + "px";
		this.line.style.left = hw / 2 + "px";
		this.line.style.width = Math.max(0, w - hw - 2)+ "px";
		if (this.line.firstChild) {
			this.line.firstChild.style.width = Math.max(0, w - hw - 4)+ "px";
		}
	}
	else {
		this.handle.style.left = (w - hw) / 2 + "px";
		if (this._inverted) {
			pos = h - hh - (h - hh) * ((this.getMaximum()-this.getMinimum()) - (this.getValue() - this.getMinimum())) / (this.getMaximum() - this.getMinimum());
		} else {
			pos = h - hh - (h - hh) * (this.getValue() - this.getMinimum()) / (this.getMaximum() - this.getMinimum());
		}
		this.handle.style.top = pos + "px";
		this.line.style.left = (w - lw) / 2 + "px";
		this.line.style.top = hh / 2 + "px";
		this.line.style.height = Math.max(0, h - hh - 2) + "px";	//hard coded border width
		if (this.line.firstChild) {
			this.line.firstChild.style.height = Math.max(0, h - hh - 4) + "px";	//hard coded border width
		}
	}
};

Slider.prototype.calculateTicks = function() {
	if (!Slider.isSupported || !this.element) return;
	for (var i = 0; i < this.ticks.length; i++) {
		this.element.removeChild(this.ticks[i]);
	}
	this.ticks = new Array();
	if (this._paintTicks) {
		if (this.getMajorTickSpacing() > 0 || this.getMinorTickSpacing() > 0) {

			var w = this.element.offsetWidth;
			var h = this.element.offsetHeight;
			var hw = this.handle.offsetWidth;
			var hh = this.handle.offsetHeight;
			var lw = this.line.offsetWidth;
			var lh = this.line.offsetHeight;

			var boundSize = (this.getMaximum() - this.getMinimum());
			var tickSpacings = [this.getMajorTickSpacing(), this.getMinorTickSpacing()];
			var startOffset = 0;
			if (this.getStyleType() == "luna") {
				startOffset = 5;
			} else if (this.getStyleType() == "swing") {
				startOffset = 7;
			} else if (this.getStyleType() == "bluecurve") {
				startOffset = 15;
			}
			for (var j = 0; j < tickSpacings.length; j++) {
				if (tickSpacings[j] > 0) {
					var nbTicks = (boundSize / tickSpacings[j]);
					if (boundSize % tickSpacings[j] == 0) {
						nbTicks++;
					}
					for (var i = 0; i < nbTicks; i++) {
						this.ticks[i] = this.document.createElement("DIV");
						this.ticks[i].className = "lineTicks";
						this.ticks[i].unselectable = "on";
						this.ticks[i].appendChild(this.document.createElement("DIV"));
						this.element.appendChild(this.ticks[i]);

						var tickSize = (j == 0) ? "8px" : "4px"; // major : minor
						
						if (this._orientation == "horizontal") {
							this.ticks[i].style.height = tickSize;
							this.ticks[i].style.width = "1px"
							this.ticks[i].style.top = (h-3) + "px";
							var size = this.element.offsetWidth - this.handle.offsetWidth;
							this.ticks[i].style.left = (((size / boundSize) * (i * tickSpacings[j])) + startOffset) + "px";
							this.ticks[i].firstChild.style.height = tickSize;

						} else {
							this.ticks[i].style.width = tickSize;
							this.ticks[i].style.height = "1px"
							this.ticks[i].style.left = (w-3) + "px";
							var size = this.element.offsetHeight - this.handle.offsetHeight;
							this.ticks[i].style.top = (((size / boundSize) * (i * tickSpacings[j])) + startOffset) + "px";
							this.ticks[i].firstChild.style.width = tickSize;
						}
					}
				}
			}
		}
	}
	this.calculateLabels();
};

Slider.prototype.calculateLabels = function() {
	if (!Slider.isSupported || !this.element) return;
	for (var i = 0; i < this.labels.length; i++) {
		this.element.removeChild(this.labels[i]);
	}
	this.labels = new Array();
	if (this._paintLabels && this.getMajorTickSpacing() > 0) {
		var w = this.element.offsetWidth;
		var h = this.element.offsetHeight;
		var hw = this.handle.offsetWidth;
		var hh = this.handle.offsetHeight;
		var lw = this.line.offsetWidth;
		var lh = this.line.offsetHeight;

		var boundSize = (this.getMaximum() - this.getMinimum());
		var tickSpacing = this.getMajorTickSpacing();
		var nbTicks = (boundSize / tickSpacing);
		var startOffsetX = 0;
		(this.getStyleType() == "luna") ? 1 : 3;
		var startOffsetY = 0;
		(this.getStyleType() == "luna") ? 1 : -1;
		if (this.getStyleType() == "luna") {
				startOffsetX = 1;
				startOffsetY = 1;
			} else if (this.getStyleType() == "swing") {
				startOffsetX = 3;
				startOffsetY = -1;
			} else if (this.getStyleType() == "bluecurve") {
				startOffsetX = 11;
				startOffsetY = -8;
			}
		for (var i = 0; i <= nbTicks; i++) {
			this.labels[i] = this.document.createElement("DIV");
			this.labels[i].className = "tickLabels";
			this.labels[i].unselectable = "on";
			this.labels[i].appendChild(this.document.createElement("DIV"));
			this.element.appendChild(this.labels[i]);
			
			var lbl = this.getMinimum() + (i*tickSpacing);
			if (this.usePrecisionFactor()) {
				lbl = (lbl/this.getPrecisionFactor()).toFixed(0);
			}
			// try to compensate for label width (which is unknown, really):
			var lbls = String(lbl);
			var plus = 0;
			switch (lbl.length) {
				case 1:
					plus = 4;
					break;
				case 2:
					plus = 1;
					break;
			}
							
			if (this._orientation == "horizontal") {
				this.labels[i].innerHTML = lbl;
				this.labels[i].style.top = (h+4) + "px";
				var size = this.element.offsetWidth - this.handle.offsetWidth;
				var n = ((this.labels[i].offsetWidth / 5) - startOffsetX) - plus;
				this.labels[i].style.left = (((size / boundSize) * (i * tickSpacing))-n) + "px";
			} else {
				this.labels[i].innerHTML = lbl;
				this.labels[i].style.left = (w+8) + "px";
				var size = this.element.offsetHeight - this.handle.offsetHeight;
				this.labels[i].style.top = (((size / boundSize) * (i * tickSpacing))-startOffsetY) + "px";
			}
		}
	}
};

Slider.prototype.ontimer = function () {
	var hw = this.handle.offsetWidth;
	var hh = this.handle.offsetHeight;
	var hl = this.handle.offsetLeft;
	var ht = this.handle.offsetTop;

	if (this._orientation == "horizontal") {
		if (this._mouseX > hl + hw &&
			(this._increasing == null || this._increasing)) {
			var plus = (this._inverted) ? 0 - this.getBlockIncrement() : this.getBlockIncrement();
			this.setValue(this.getValue() + plus);
			this._increasing = true
		}
		else if (this._mouseX < hl &&
			(this._increasing == null || !this._increasing)) {
			var plus = (this._inverted) ? this.getBlockIncrement() : 0 - this.getBlockIncrement();
			this.setValue(this.getValue() + plus);
			this._increasing = false;
		}
	}
	else {
		if (this._mouseY > ht + hh &&
			(this._increasing == null || !this._increasing)) {
			var plus = (this._inverted) ? this.getBlockIncrement() : 0 - this.getBlockIncrement();
			this.setValue(this.getValue() + plus);
			this._increasing = false;
		}
		else if (this._mouseY < ht &&
			(this._increasing == null || this._increasing)) {
			var plus = (this._inverted) ? 0 - this.getBlockIncrement() : this.getBlockIncrement();
			this.setValue(this.getValue() + plus);
			this._increasing = true;
		}
	}

	this._timer.start();
};

Slider.prototype.isInDrag = function() {
	return Slider._sliderDragData != null;
};

Slider.prototype.initEvents = function() {
	var oElement = this.element;
	
	// events
	var oThis = this;
	if (this.isEnabled()) {
		this._range.onchange = function () {
			oThis.recalculate();
		};
	} else {
		this._range.onchange = null;
	}

	if (Slider.isSupported && oElement) {
		this.element.onfocus		= (this.isEnabled()) ? Slider.eventHandlers.onfocus : null;
		this.element.onblur			= (this.isEnabled()) ? Slider.eventHandlers.onblur : null;
		this.element.onmousedown	= (this.isEnabled()) ? Slider.eventHandlers.onmousedown : null;
		this.element.onmouseover	= (this.isEnabled()) ? Slider.eventHandlers.onmouseover : null;
		this.element.onmouseout		= (this.isEnabled()) ? Slider.eventHandlers.onmouseout : null;
		this.element.onkeydown		= (this.isEnabled()) ? Slider.eventHandlers.onkeydown : null;
		this.element.onkeypress		= (this.isEnabled()) ? Slider.eventHandlers.onkeypress : null;
		this.element.onmousewheel	= (this.isEnabled()) ? Slider.eventHandlers.onmousewheel : null;
		this.handle.onselectstart	=
		this.element.onselectstart	= function () { return false; };

		if (this._enabled) {
			this._timer.ontimer = function () {
				oThis.ontimer();
			};

			// extra recalculate for ie
			window.setTimeout(function() {
				oThis.recalculate();
			}, 1);
		}
	}
	else {
		if (this.isEnabled()) { 
			this.input.onchange = function (e) {
				oThis.setValue(oThis.getExternalValue());
			};
		} else {
			this.input.onchange = null;
		}
	}
	this.updateEnabledSupport();
};

Slider.prototype.format_number = function (v) {
	var s = new String(v.toFixed(this.getPrecision()));
	while ((s.substr(s.length -1,1) == '0' || s.substr(s.length -1,1) == '.') && s.length > 1) {
		var e = s.substr(s.length -1,1);
		s = s.substring(0, s.length-1);
		if (e == '.') break;
	}
	return s;
};
